package com.zeyu.framework.tools.generate;

import com.mysql.jdbc.Driver;
import org.junit.Test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.GeneratedKey;
import org.mybatis.generator.config.JDBCConnectionConfiguration;
import org.mybatis.generator.config.JavaClientGeneratorConfiguration;
import org.mybatis.generator.config.JavaModelGeneratorConfiguration;
import org.mybatis.generator.config.ModelType;
import org.mybatis.generator.config.PluginConfiguration;
import org.mybatis.generator.config.SqlMapGeneratorConfiguration;
import org.mybatis.generator.config.TableConfiguration;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.generator.MapperPlugin;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * generate mybatis mapper entity and xml
 * Created by zeyuphoenix on 2017/1/23.
 */
public class MyBatisGenerate {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * logger
     */
    private static final Logger logger = LoggerFactory.getLogger(MyBatisGenerate.class);

    // ================================================================
    // Fields
    // ================================================================

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    @Test
    public void generate() {

        logger.info("generate mybatis auto xml、entity、mapper start...");

        // SQL通配符%来匹配所有表
        // String tableName = "%";
        String tableName = "tb_auto_test";

        // 数据库连接url地址
        String url = "jdbc:mysql://127.0.0.1:3306/framework?characterEncoding=utf-8&useSSL=true";
        // 数据库连接用户名和密码
        String username = "root";
        String password = "123456";
        // 数据源驱动类可不写，Druid默认会自动根据URL识别DriverClass
        String dirver = "com.mysql.jdbc.Driver";

        try {
            Resource resource = new ClassPathResource("application.properties");

            URL path = resource.getURL();
            logger.info("application.properties path is {} ", path);

            Properties properties = new Properties();
            properties.load(resource.getInputStream());

            url = properties.getProperty("spring.datasource.url");
            username = properties.getProperty("spring.datasource.username");
            password = properties.getProperty("spring.datasource.password");
            dirver = properties.getProperty("spring.datasource.driver-class-name");

        } catch (Exception e) {
            logger.error("", e);
        }


        List<String> warnings = new ArrayList<>();

        // 生成的主配置
        Configuration config = new Configuration();

        // context
        // 该模型为每一张表只生成一个实体类。这个实体类包含表中的所有字段
        Context context = new Context(ModelType.FLAT);
        // context唯一的标识符。此值将用于某些错误消息
        context.setId("mysql");
        // 指定生成的代码的运行时目标
        context.setTargetRuntime("MyBatis3Simple");

        // Mapper的插件
        PluginConfiguration pluginConfiguration = new PluginConfiguration();
        context.addPluginConfiguration(pluginConfiguration);
        // 配置通用Mapper的插件
        pluginConfiguration.setConfigurationType(MapperPlugin.class.getName());
        // 使用的通用Mapper接口，多个通用Mapper接口可以用逗号隔开
        pluginConfiguration.addProperty("mappers", Mapper.class.getName());
        // caseSensitive默认false，当数据库表名区分大小写时，可以将该属性设置为true
        pluginConfiguration.addProperty("caseSensitive", "true");

        // 数据库配置信息
        JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
        context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);
        if (dirver == null) {
            jdbcConnectionConfiguration.setDriverClass(Driver.class.getName());
        } else {
            jdbcConnectionConfiguration.setDriverClass(dirver);
        }
        // 数据库连接信息,可以通过读取spring配置文件获得
        jdbcConnectionConfiguration.setConnectionURL(url);
        jdbcConnectionConfiguration.setUserId(username);
        jdbcConnectionConfiguration.setPassword(password);

        // 生成实体类的配置
        JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = new JavaModelGeneratorConfiguration();
        context.setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration);
        String targetPackage = "generate.entity";
        String targetProject = "src/test/java";
        javaModelGeneratorConfiguration.setTargetPackage(targetPackage);
        javaModelGeneratorConfiguration.setTargetProject(targetProject);

        // 生成Mapper接口对应的XML文件
        SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = new SqlMapGeneratorConfiguration();
        context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration);
        targetPackage = "mappers";
        targetProject = "src/test/resources";
        sqlMapGeneratorConfiguration.setTargetPackage(targetPackage);
        sqlMapGeneratorConfiguration.setTargetProject(targetProject);

        // 生成对应的接口文件，该接口会自动继承前面配置的通用Mapper接口
        JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();
        context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);
        targetPackage = "generate.dao";
        targetProject = "src/test/java";
        // 生成的对象是 MyBatis 3.x 映射器基础结构的 Java接口。 这些接口将会依赖于生成的XML文件
        javaClientGeneratorConfiguration.setConfigurationType("XMLMAPPER");
        javaClientGeneratorConfiguration.setTargetPackage(targetPackage);
        javaClientGeneratorConfiguration.setTargetProject(targetProject);
        javaClientGeneratorConfiguration.setImplementationPackage(null);

        // 配置table
        TableConfiguration tc = new TableConfiguration(context);
        context.addTableConfiguration(tc);
        // SQL通配符%来匹配所有表
        tc.setTableName(tableName);
        // generatedKey意味着所有的表都有一个id自增的主键，在生成实体类的时候会根据该配置生成相应的注解
        // 1. 生成列的列名
        // 2. 将返回新值的 SQL 语句。如果这是一个identity列，您可以使用其中一个预定义的的特殊值
        // 3. 设置为 true 时,该列会被标记为identity列
        GeneratedKey gk = new GeneratedKey("id", "Mysql", false, null);
        tc.setGeneratedKey(gk);

        config.addContext(context);

        DefaultShellCallback callback = new DefaultShellCallback(true);
        try {
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);
        } catch (Exception e) {
            e.printStackTrace();
        }

        logger.info("generate mybatis auto xml、entity、mapper finish");
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================

}
